// ignore_for_file: deprecated_member_use

import 'package:analyzer/dart/ast/ast.dart';
import 'package:dart_bean/generator.dart';
import 'package:dart_bean/util/error_tip.dart';
import 'package:dart_bean/util/ext.dart';
import 'package:dart_bean/util/field_feature.dart';
import 'package:dart_bean/field_info.dart';
import 'package:json_annotation/json_annotation.dart';

class JsonKeyFeature extends FieldFeature {
  @override
  String? getJsonName(FieldInfo field) {
    return _getJsonKey(field).name;
  }

  @override
  bool? isIgnoreDeserialize(FieldInfo field) {
    return _isIgnore(field, true);
  }

  @override
  bool? isIgnoreSerialize(FieldInfo field) {
    return _isIgnore(field, false);
  }

  bool _isIgnore(FieldInfo field, bool fromJson) {
    final jf = _getJsonKey(field);
    return jf.ignore == true || (fromJson && jf.includeFromJson == false) || (!fromJson && jf.includeToJson == false);
  }

  JsonKey _getJsonKey(FieldInfo field) {
    var jsonField = field.buffers[JsonKey] as JsonKey?;
    if (jsonField != null) return jsonField;

    final Map<String, dynamic> map = {};
    final jf = field.self.metadata.firstOrNull((e) => e.name.name == 'JsonKey');
    if (jf != null) {
      final args = jf.arguments?.arguments;
      if (args != null) {
        for (var e in args) {
          final ne = e as NamedExpression;
          final name = ne.name.label.name;
          final v = ne.expression;
          if (v is StringLiteral) {
            map[name] = v.stringValue;
          } else if (v is BooleanLiteral) {
            map[name] = v.value;
          } else if (v is NullLiteral) {
            map[name] = null;
          } else {
            map[name] = v.toString();
          }
        }
      }
    }
    jsonField = JsonKey(
      name: map.remove('name'),
      ignore: map.remove('ignore'),
      includeToJson: map.remove('includeToJson'),
      includeFromJson: map.remove('includeFromJson'),
    );
    _checkIncompatibleType(field, map);
    field.buffers[JsonKey] = jsonField;
    return jsonField;
  }

  static final _onlySupported = 'SUPPORTED ONLY: name, ignore, includeToJson, includeFromJson';

  void _checkIncompatibleType(FieldInfo field, Map<String, dynamic> map) {
    for (var type in map.keys) {
      String msg;
      if (type == 'defaultValue' || type == 'unknownEnumValue') {
        msg = """
${fieldErrorInfo(field)}
  $unsupportedJsonKeyFeatureError
  JsonKey.$type is not supported,
  please set default value when declare field,
  eg: ColorEnum c = ColorEnum.unknown;
  
  $_onlySupported""";
      } else {
        msg = """
${fieldErrorInfo(field)}
  $unsupportedJsonKeyFeatureError
  JsonKey.$type is not supported,
  $_onlySupported""";
      }
      onError(msg);
    }
  }
}
